﻿using System.Data;
using System.Dynamic;
using System.Reflection;

namespace NET6.WebAPI.Extensions
{
    public static class DataTableExtension
    {
        /// <summary>
        /// 为 DataTable 添加序号列
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static DataTable AddSequenceColumn(this DataTable? dt)
        {
            var newDt = new DataTable();

            if (dt == null) return newDt;

            string colName = "序号";

            if (dt.Columns.Count == 0 || dt.Columns.Contains(colName))
            {
                return dt;
            }

            #region 添加逻辑

            // 添加序号列
            newDt.Columns.Add(colName, typeof(int));

            // 添加其他列
            foreach (DataColumn col in dt.Columns)
            {
                newDt.Columns.Add(col.ColumnName, col.DataType);
            }

            // 添加序号和行
            foreach (DataRow row in dt.Rows)
            {
                DataRow newRow = newDt.NewRow();
                newRow[colName] = newDt.Rows.Count + 1;

                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    newRow[dt.Columns[i].ColumnName] = row[i];
                }

                newDt.Rows.Add(newRow);
            }

            #endregion

            return newDt;
        }

        /// <summary>
        /// DataTable 转 List
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<dynamic> ToList(this DataTable? dt)
        {
            var list = new List<dynamic>();

            if (dt == null || dt.Rows.Count == 0)
            {
                return list;
            }

            foreach (DataRow row in dt.Rows)
            {
                IDictionary<string, object?> item = new ExpandoObject();

                foreach (DataColumn col in dt.Columns)
                {
                    var val = row[col];
                    if (val is DBNull) 
                    {
                        val = null;
                    }

                    item[col.ColumnName] = val;
                }

                list.Add(item);
            }

            return list;
        }

        /// <summary>
        /// DataTable 转 List
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<T> ToList<T>(this DataTable? dt) where T : new()
        {
            var list = new List<T>();

            if (dt == null || dt.Rows.Count == 0)
            {
                return list;
            }

            #region 转换逻辑

            var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (DataRow row in dt.Rows)
            {
                var obj = new T();

                foreach (PropertyInfo prop in props)
                {
                    if (!(dt.Columns.Contains(prop.Name) && prop.CanWrite))
                    {
                        continue;
                    }

                    var val = row[prop.Name];
                    if (val is DBNull)
                    {
                        prop.SetValue(obj, null);
                    }
                    else
                    {
                        try
                        {
                            prop.SetValue(obj, Convert.ChangeType(val, prop.PropertyType));
                        }
                        catch (SystemException)
                        {
                            prop.SetValue(obj, default);
                        }
                    }
                }

                list.Add(obj);
            }

            #endregion

            return list;
        }
    }
}
